#pragma once
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstring>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

extern Log log;
const int default_sockfd = -1;
const uint16_t default_port = 8000;
const std::string default_ip = "0.0.0.0";
int backlog = 5;
enum
{
    SOCK_ERR = 1,
    BIND_ERR,
    LISTEN_ERR,
    USAGE_ERR
};
class TcpServer;
class ThreadData
{
public:
    ThreadData(TcpServer* tcpserver, int sockfd, const std::string& clientip, uint16_t &clientport)
    :_tcpserver(tcpserver),_sockfd(sockfd),_clientip(clientip),_clientport(clientport)
    {}
public:
    TcpServer* _tcpserver;
    int _sockfd;
    std::string _clientip;
    uint16_t _clientport;
};
class TcpServer
{
public:
    TcpServer(int sockfd = default_sockfd, const std::string &serverip = default_ip, uint16_t serverport = default_port)
        :_listensockfd(sockfd), _serverip(serverip), _serverport(serverport)
    {
    }
    ~TcpServer()
    {
    }

    void Init()
    {
        // 1.创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd == -1)
        {
            log(Fatal, "socket fail, errnor:%d, strerror:%s\n", errno, strerror(errno));
            exit(SOCK_ERR);
        }
        log(Info, "socket create success, fd:%d\n", _listensockfd);

        // bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_serverport);
        inet_aton(_serverip.c_str(), &(local.sin_addr));

        if (bind(_listensockfd, (struct sockaddr *)&local, sizeof(local)) == -1)
        {
            log(Fatal, "bind fail, errnor:%d, strerror:%s\n", errno, strerror(errno));
            exit(BIND_ERR);
        }
        log(Info, "bind success\n");

        // 设置监听状态
        if (listen(_listensockfd, backlog) == -1)
        {
            log(Fatal, "listen fail, errno:%d, strerror:%s\n", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
    }

    void Start()
    {
        ThreadPool<Task>::GetInstance()->Start();
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensockfd, (struct sockaddr *)&client, &len);
            if (sockfd == -1)
            {
                log(Warning, "accept fail, errno:%d, strerror:%s\n", errno, strerror(errno));
                continue;
            }
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(client));
            uint16_t clientport = ntohs(client.sin_port);
            log(Info, "[%s:%d]accept success\n", clientip, clientport);

            // version1 --单进程版本
            //  Service(sockfd, clientip, clientport);
            //  close(sockfd);

            // version2 -- 多进程版本
            //  pid_t id = fork();
            //  if (id == 0)
            //  {
            //      // child
            //      close(_listensockfd);
            //      if(fork() > 0) exit(0);//优雅
            //      Service(sockfd, clientip, clientport);
            //      exit(0);
            //  }
            //  // farther
            //  //waitpid(id, nullptr, 0);
            //  close(sockfd);

            // 多线程版本
            // pthread_t tid;
            // //ThreadData td(this, sockfd, clientip, clientport);??????
            // ThreadData* td = new ThreadData(this, sockfd, clientip, clientport);
            // pthread_create(&tid, nullptr, routine, td);

            //线程池版本
            Task task(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(task);

        }
    }
    // static void *routine(void *arg)
    // {
    //     ThreadData* td = static_cast<ThreadData*>(arg);
    //     pthread_self();
    //     td->_tcpserver->Service(td->_sockfd, td->_clientip, td->_clientport);
    //     return nullptr;
    // }
    // void Service(int sockfd, std::string& clientip, uint16_t &clientport)
    // {
    //     char buffer[1024];
    //     std::string info;
    //     while (true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if (n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "server get a message:" << buffer << std::endl;
    //         }
    //         else if(n == 0)
    //         {
    //             log(Info, "[%s:%d]quit, server close sockfd:%d\n", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         else if(n < 0)
    //         {
    //             log(Warning, "read error, clientip:%s, clientport:%d, sockfd:%d\n", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         std::string message = buffer;
    //         info = "还给你:" + message;
    //         write(sockfd, info.c_str(), info.size());
    //     }
    //}

private:
    int _listensockfd;
    uint16_t _serverport;
    std::string _serverip;
};